
// new Vue({el:'', data: '', ...})
// Dep 依赖
// 编译 compile

class Myvue{
    constructor(options) {
        this.$options = options
        this.$data = options.data
        // 响应化
        // observe 观察， 监听函数
        this.observe(this.$data)

        // 模拟一下watcher创建
        // new Watcher()
        // this.$data.test
        // new Watcher()
        // this.$data.foo.bar

        new Compile(this.$options.el, this)
        if (options.created) {
            options.created.call(this)
        }
    }

    // 观察监听函数
    observe(value) {
        if(!value || typeof value !== 'object'){
            return
        }

        // 遍历对象
        Object.keys(value).forEach(key => {
            // this.observe(value[key])
            this.defienReactive(value, key, value[key])
            // 定义代理， 把data 代理到 this vue实例上
            this.proxyData(key)
        })
    }

    proxyData(key){
        Object.defineProperty(this, key, {
            get(){
                return this.$data[key]
            },
            set(newVal){
                this.$data[key] = newVal
            }
        })
    }

    // 数据响应化
    // 定义响应化
    defienReactive(obj, key, val) {
        // now  解决数据嵌套，用递归
        this.observe(val)

        // 初始化 Dep
        // 相对独立的，相对于 key 的函数作用域
        const dep = new Dep()
        /**
         * 相当于是在一个函数作用域下面，
         * 定义一个 key 的时候，作用域就是找个 key 下面的
         */

        // 数据劫持
        Object.defineProperty(obj, key, {
            get(){
                // console.log('get触发了')
                Dep.target && dep.addDep(Dep.target)
                return val
            },
            set(newVal){
                if(newVal === val) {
                    return
                }
                // obj[key] = newVal
                val = newVal
                // console.log(`${key}属性更新了，新值是 ${newVal}`)
                dep.notify()
            }
        })
    }

    // 依赖收集 / 更新
}

// 依赖对象 dependce
// 用来管理Watcher
// 类似Watcher观察者的总管家 观察者的集合
class Dep{
    constructor(){
        // 存放若干依赖(watcher) // 再此一个watcher对应一个属性，也就是data里面定义的属性
        this.deps = []
    }

    // 收集依赖的
    addDep(dep){
        this.deps.push(dep)
    }

    // 通知方法
    // 用来通知所有的watcher依赖进行更新
    notify(){
        this.deps.forEach(dep => dep.update())
    }
}
// 观察者 watcher
// watcher 是用来做具体调用更新的对象
class Watcher{
    constructor(vm, key, cb) {
        this.vm = vm
        this.key = key
        this.cb = cb
        // Dep的静态属性
        // 将当前watcher实例指定到Dep的静态属性target上
        // 静态属性只会有一个
        Dep.target = this
        // 读取一下数据，触发getter
        this.vm[this.key]
        Dep.target = null
    }

    update(){
        // console.log('属性更新了')
        this.cb.call(this.vm, this.vm[this.key])
    }
}
